package com.apes.enquiry.product.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.enquiry.brand.repository.SpBrandRepository;
import com.apes.enquiry.product.model.OilyProduct;
import com.apes.enquiry.product.model.SpProduct;
import com.apes.enquiry.product.repository.OilyProductRepository;
import com.apes.enquiry.product.repository.SpProductRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.apestech.framework.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 类描述：
 *
 * @ClassName OilyProductService
 * @Description 描述
 * @Author wushilong
 * @Date 2022/11/1 14:40
 * @Version 1.0
 */
@Service
public class OilyProductService extends DomainService {

    @Autowired
    private SpBrandRepository spBrandRepository;

    @Autowired
    private OilyProductRepository oilyProductRepository;

    @Autowired
    private SpProductRepository spProductRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 上传机油类商品入口
     *
     * @param request
     */
    public void uploadingOilyProduct(SimpleRequest request) {
        //Excel信息
        JSONObject importData = request.get("importData");
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));

        //准入校验与数据补全
        List oilyProducts = appendImportReturn_New(importData, user);
        if (oilyProducts.size() <= 0) return;
        List oilyProduct = Collections.synchronizedList(new ArrayList());
        for(int i=0;i<oilyProducts.size();i++){
            oilyProduct.add(oilyProducts.get(i));
            if((i!=0 && i%1000==0) || i==oilyProducts.size()-1){
                SimpleDateFormat sdf = new SimpleDateFormat("yy-mm-dd HH:mm:ss");
                //通过事务发件箱实现标准对照/状态字段回写
                OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
                wrapper.setSubscriber("sp.oilyProduct.standardContrast");
                String random = String.valueOf(Math.random()).substring(0,3);
                //聚合根ID（非必项）tp:方便追溯发生异常的服务,(当前用户账号加时间戳)
                wrapper.setAggregateId(user.getOrigin() + sdf.format(new Date())+random);
                wrapper.setPayload(JSON.toJSONString(oilyProduct));
                SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
                oilyProduct=Collections.synchronizedList(new ArrayList());
            }
        }
    }

    /**
     * 准入校验与数据补全
     *
     * @param importData
     * @param user
     * @return
     */
    private List appendImportReturn_New(JSONObject importData, User user) {
        List oilyProducts = Collections.synchronizedList(new ArrayList());
        List notProducts = Collections.synchronizedList(new ArrayList());
        //零件号+品牌列表
        Set<String> PNAndBrand = spProductRepository.findPNAndBrandAll();
        //品牌列表
        List<String> allName = spBrandRepository.findAllName();

        //开始校验数据
        importData.forEach((k, v) -> {
            JSONArray importArray = (JSONArray) v;
            if(((JSONArray) importArray.get(0)).size()!=17) throw new RuntimeException("导入模板错误，请检查文件并重新上传！");
            if (importArray.size() > 10000) throw new RuntimeException("系统单次导入最大可以接受1W条数据，请检查文件大小并重新上传！");
            AtomicInteger i = new AtomicInteger(0);
            double size = importArray.size();
            importArray.parallelStream().forEach(item -> {
                JSONArray iValueArray = (JSONArray) item;

                //进度条
                i.getAndIncrement();
                double percent = (i.get() / size) * 100;
                int progress = (int) percent;
                stringRedisTemplate.opsForValue().set("OilyProduct" + user.getOrigin(), "" + progress, 2, TimeUnit.MINUTES);

                //跳过列名和导入规则行
                if (iValueArray.size() < 3 || "零件号".equals(iValueArray.getString(0)) ||
                        "“零件号”必填，如果是原厂件类请填写原厂件号，如果是品牌件请填写品牌件号，同品牌内零件号不可重复".equals(iValueArray.getString(0))) return;
                String GuaranteePeriod = "";
                for (int n = 0; n < iValueArray.size(); n++) {
                    if (Objects.isNull(iValueArray.get(n))) continue;
                    switch (n) {
                        case 11: GuaranteePeriod = iValueArray.getString(11);
                            break;
                    }
                }
                //0、零件号 1、品牌 2、商品名称 3、商家编码 4、系列 5、型号 6、容量 7、API等级 8、粘度等级 9、类型 10、机油类型 11、产品描述 12、库存数量 13、不含税单价 14、上架状态
                String[] strings = {iValueArray.getString(1), iValueArray.getString(9), iValueArray.getString(10)};
                if (iValueArray.size() > 10 && UploadingProductUtil.isAllNotEmpty(iValueArray.getString(0), iValueArray.getString(1),
                        iValueArray.getString(4), iValueArray.getString(6), iValueArray.getString(7), iValueArray.getString(8), iValueArray.getString(9),
                        iValueArray.getString(10))&&("".equals(GuaranteePeriod)||"0".equals(GuaranteePeriod)||"1".equals(GuaranteePeriod)||"3".equals(GuaranteePeriod)||
                        "6".equals(GuaranteePeriod)||"12".equals(GuaranteePeriod)||"24".equals(GuaranteePeriod)) && this.formatCheck(strings, allName) && this.digitCheck(iValueArray.getString(6))
                        && PNAndBrand.add(iValueArray.getString(0) + iValueArray.getString(1) + user.getPerson().getId())) {


                    //数据初始化与数据补全
                    //主数据数据补全
                    SpProduct spProduct = new SpProduct();
                    spProduct.setName(iValueArray.getString(2));
                    spProduct.setSupplier(user.getPerson());
                    spProduct.setType("机油");
                    spProduct.setSpBrand(spBrandRepository.findByName(iValueArray.getString(1)));
                    spProduct.setQuality(spProduct.getSpBrand().getQualityName());
                    spProduct.setOE(iValueArray.getString(0));
                    if(GuaranteePeriod.equals("")){
                        spProduct.setGuaranteePeriod("0");
                    }else{
                        spProduct.setGuaranteePeriod(GuaranteePeriod);
                    }
                    spProduct.setMerchantProduct(iValueArray.getString(3));
                    maybe(iValueArray, spProduct);
                    spProduct.setMateState("underway");
                    spProduct.setProductState("review");
                    spProduct.setStandardType("Oily");

                    OilyProduct oilyProduct = new OilyProduct();
                    oilyProduct.setSpProduct(spProductRepository.saveAndFlush(spProduct));
                    oilyProduct.setCatena(iValueArray.getString(4));
                    oilyProduct.setModel(iValueArray.getString(5));
                    oilyProduct.setCapacity(iValueArray.getDouble(6));
                    oilyProduct.setApiClass(iValueArray.getString(7));
                    oilyProduct.setViscosityClass(iValueArray.getString(8));
                    oilyProduct.setType(iValueArray.getString(9));
                    oilyProduct.setEngineOilType(iValueArray.getString(10));

                    //保存
                    oilyProducts.add(oilyProductRepository.save(oilyProduct));
                } else {
                    notProducts.add(UploadingProductUtil.oilyCause(iValueArray, allName, PNAndBrand, user.getPerson().getId()));
                }
            });
        });

        oilyProductRepository.flush();
        //用Redis，缓存进度条和结果
        stringRedisTemplate.opsForValue().set("not_oilyProducts" + user.getOrigin(), notProducts.toString(), 2, TimeUnit.HOURS);
        //进度条
        stringRedisTemplate.opsForValue().set("OilyProduct" + user.getOrigin(), "100", 2, TimeUnit.MINUTES);
        //用于结果页面展示
        stringRedisTemplate.opsForValue().set("successfulOily" + user.getOrigin(), "" + oilyProducts.size(), 4, TimeUnit.MINUTES);
        stringRedisTemplate.opsForValue().set("failingOily" + user.getOrigin(), "" + notProducts.size(), 4, TimeUnit.MINUTES);
        return oilyProducts;
    }

    private void maybe(JSONArray iValueArray, SpProduct spProduct) {
        spProduct.setNotTaxUnitPrice(0.00);
        spProduct.setMerchantStockQty(0);
        spProduct.setPutawayState(false);
        switch (iValueArray.size()){
            case 12:{
                spProduct.setDescribe(iValueArray.getString(11));
                break;
            }
            case 13:{
                spProduct.setDescribe(iValueArray.getString(11));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(12)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(12)) ? iValueArray.getInteger(12) : 0);
                break;
            }
            case 14:{
                spProduct.setDescribe(iValueArray.getString(11));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(12)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(12)) ? iValueArray.getInteger(12) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(13)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(13)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(13))) : 0);
                break;
            }
            case 15:{
                spProduct.setDescribe(iValueArray.getString(11));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(12)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(12)) ? iValueArray.getInteger(12) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(13)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(13)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(13))) : 0);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(14)));
                break;
            }
            case 16:{
                spProduct.setDescribe(iValueArray.getString(11));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(12)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(12)) ? iValueArray.getInteger(12) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(13)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(13)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(13))) : 0);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(14)));
                spProduct.setDescribe(iValueArray.getString(15));
                break;
            }
            case 17:{
                spProduct.setDescribe(iValueArray.getString(11));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(12)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(12)) ? iValueArray.getInteger(12) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(13)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(13)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(13))) : 0);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(14)));
                spProduct.setDescribe(iValueArray.getString(15));
                break;
            }
        }
    }


    /**
     * 标准对照与字段回写
     *
     * @param outboxPayloadWrapper
     */
    @OutboxSubscriber(id = "sp.oilyProduct.standardContrast", name = "通过事务发件箱实现标准对照/状态字段回写")
    public void standardContrast(OutboxPayloadWrapper outboxPayloadWrapper) {
        //导入商品数据
        JSONArray importData = JSON.parseArray(outboxPayloadWrapper.getPayload());

        if (importData.size() <= 0) return;
        //数据中心标准数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("key", "value");
        JSONObject json = JSON.parseObject(super.invoke("cm.oilyProduct.findAllByStandard", jsonObject));
        JSONArray body = json.getJSONArray("body");
        Set<String> set = new HashSet<>();
        //数据对比与状态回写
        Map<String, JSONObject> conditionMap = body.parallelStream().filter(data -> {
            JSONObject oily = (JSONObject)data;
            String upperCase = (oily.getString("brand") + oily.getString("viscosityClass") +
                    oily.getString("apiClass") + oily.getString("type") + oily.getString("capacity")).toUpperCase();
            return Objects.nonNull(data) && set.add(upperCase);
        }).collect(Collectors.toMap(item -> {
                    JSONObject oilyProduct = (JSONObject) item;
                    return (oilyProduct.getString("brand") + oilyProduct.getString("viscosityClass") +
                            oilyProduct.getString("apiClass") + oilyProduct.getString("type") + oilyProduct.getString("capacity")).toUpperCase();
                },
                item -> {
                    JSONObject oilyProduct = (JSONObject) item;
                    return oilyProduct;
                }));

        //匹配
        importData.stream().forEach(item -> {
            String id = ((JSONObject) item).getString("id");
            OilyProduct oilyProduct = null;
                    if(StringUtil.isEmpty(((JSONObject) item).getString("oE"))){
                         oilyProduct = oilyProductRepository.findOne(id);
                    }else{
                        oilyProduct = oilyProductRepository.findBySpId(id);
                    }
                if(oilyProduct!=null){
                    JSONObject normalData = conditionMap.get((oilyProduct.getSpProduct().getSpBrand().getName() + oilyProduct.getViscosityClass() + oilyProduct.getApiClass() +
                            oilyProduct.getType() + oilyProduct.getCapacity()).toUpperCase());

                    if (Objects.nonNull(normalData)) {
                        //匹配成功
                        SpProduct spProduct = oilyProduct.getSpProduct();
                        spProduct.setMateState("succeed");
                        spProduct.setProductState(spProduct.isPutawayState() ? "offer" : "awaitPutaway");
                        spProduct.setStandardId(normalData.getString("id"));
                        spProductRepository.saveAndFlush(spProduct);
                    } else {
                        //匹配失败
                        SpProduct spProduct = oilyProduct.getSpProduct();
                        spProduct.setMateState("fail");
                        spProduct.setProductState("notOffer");
                        spProductRepository.saveAndFlush(spProduct);
                    }
                }
        });
    }

    /**
     * String格式校验
     *
     * @param strings
     * @return
     */
    public boolean formatCheck(String[] strings, List<String> allName) {
        if (strings.length == 0) {
            return false;
        }

        for (String item : strings) {
            if (Objects.isNull(item)) continue;
            if (allName.contains(item) || "汽机油、柴机油、柴汽通用机油".contains(item) || "矿物油、半合成机油、全合成机油".contains(item)) {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * 校验数字
     *
     * @param strings
     * @return
     */
    public boolean digitCheck(String... strings) {
        if (strings.length == 0) {
            return false;
        }
        for (String item : strings) {
            if (!Pattern.matches("^\\d+(\\.\\d+)?$", item)) {
                return false;
            }
        }
        return true;
    }


    /**
     * 进度条
     *
     * @return
     */
    public String progress(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        String progressBar = stringRedisTemplate.opsForValue().get("OilyProduct" + user.getOrigin());
        if ("100".equals(progressBar)) stringRedisTemplate.delete("OilyProduct" + user.getOrigin());
        return progressBar;
    }

    /**
     * 上传结果
     *
     * @param request
     * @return
     */
    public String resultPage(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        return "本次成功导入" + stringRedisTemplate.opsForValue().get("successfulOily" + user.getOrigin()) +
                "条\n" + "导入失败" + stringRedisTemplate.opsForValue().get("failingOily" + user.getOrigin()) + "条";
    }

    /**
     * 下载失败结果
     *
     * @param request
     * @return
     */
    public Map detail(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        String oilyProducts = stringRedisTemplate.opsForValue().get("not_oilyProducts" + user.getOrigin());
        JSONArray objects = JSONArray.parseArray(oilyProducts);
        assert objects != null;
        stringRedisTemplate.delete("not_oilyProducts" + user.getOrigin());
        return MapUtil.mapper("content", new ArrayList<>(objects), "total", objects.size(), "pages", request.get("page"));
    }

}
